﻿namespace Pottery.Module.Infrastructure.Models
{
    using System;
    using System.Runtime.Serialization;
    using System.Text.RegularExpressions;
    using Pottery.Model.Infrastructure;
    using Pottery.Module.Infrastructure.Models;

    [DataContract]
    public class User : Human, IAssignable, IValidatable, IEquatable<User>
    {
        #region Constructors

        /// <summary>
        /// Initializes new default instance of User
        /// </summary>
        public User() : base() { }

        /// <summary>
        /// Initializes new instance of User
        /// </summary>
        /// <param name="login">User's login</param>
        /// <param name="password">User's password</param>
        /// <param name="firstName">User's name</param>
        /// <param name="lastName">User's surname</param>
        /// <param name="email">User's email</param>
        /// <param name="newProductsReporting">User's agreement with reporting about new goods in catalog</param>
        public User(string login, string password, string firstName, string lastName,
                    string email, bool newProductsReporting)
            : this(login, password, firstName, lastName, email, string.Empty, string.Empty, null, newProductsReporting) { }


        /// <summary>
        /// Initializes new instance of User
        /// </summary>
        /// <param name="login">User's login</param>
        /// <param name="password">User's password</param>
        /// <param name="firstName">User's name</param>
        /// <param name="lastName">User's surnam</param>
        /// <param name="email">User's email</param>
        /// <param name="address">User's address</param>
        /// <param name="phone">User's phone</param>
        /// <param name="photo">User's photo</param>
        /// <param name="newProductsReporting">User's agreement with reporting about new goods in catalog</param>
        public User(string login, string password, string firstName, string lastName,
                    string email, string address, string phone, byte[] photo,
                    bool newProductsReporting)
            : base(login, password, firstName, lastName, email, address, phone, photo)
        {

            NewProductsReporting = newProductsReporting;
            StatusChangeDate = DateTime.Now;
        }

        #endregion

        #region Properties

        [DataMember(Order = 1)]
        public Enumerators.UserStatus UserStatus
        {
            get
            {
                return m_UserStatus;
            }
            set
            {
                m_UserStatus = value;
            }
        }

        [DataMember(Order = 2)]
        public bool NewProductsReporting
        {
            get
            {
                return m_NewProductsReporting;
            }
            set
            {
                m_NewProductsReporting = value;
            }
        }

        [DataMember(Order = 2)]
        public DateTime StatusChangeDate
        {
            get
            {
                return m_StatusChangeDate;
            }
            set
            {

                m_StatusChangeDate = value;
            }
        }


        [DataMember(Order = 3)]
        public int Discount
        {
            get
            {
                return m_Discount;
            }
            set
            {
                m_Discount = value;
            }
        }

        #endregion

        #region IAssignable Implementation

        /// <summary>
        /// Content transfer
        /// </summary>
        /// <param name="obj">Object that takes content</param>
        /// <exception cref="ArgumentNullException">If object, that takes content is a null object </exception>
        /// <exception cref="NotSupportedException">If object, that takes content isn'tsupported by method</exception>
        public void AssignTo(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException();

            if (obj is User)
            {
                User user = obj as User;
                user.Login = Login;
                user.FirstName = FirstName;
                user.LastName = LastName;
                user.Email = Email;
                user.Password = Password;
                user.Address = Address;
                user.m_Discount = m_Discount;
                user.m_NewProductsReporting = m_NewProductsReporting;
                user.Phone = Phone;
                user.Photo = Photo;
                user.RegistrationDate = RegistrationDate;
                user.m_StatusChangeDate = m_StatusChangeDate;
                user.UserStatus = UserStatus;

                return;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region IValidatable Implementation

        /// <summary>
        /// Validates current User
        /// </summary>
        /// <returns>True - if User is valid, otherwise - False</returns>
        public bool Validate()
        {
            bool result = true;

            if (string.IsNullOrEmpty(Login) || string.IsNullOrWhiteSpace(Login))
                result = false;

            if (Login.Length < ModelConstants.MIN_LOGIN_LENGTH || Login.Length > ModelConstants.MAX_LOGIN_LENGTH)
                result = false;

            if (Login.Contains(ModelConstants.SPACE))
                result = false;

            if (string.IsNullOrEmpty(FirstName) || string.IsNullOrWhiteSpace(FirstName))
                result = false;

            if (FirstName.Length > ModelConstants.MAX_FIRST_NAME_LENGTH)
                result = false;

            if (FirstName.Contains(ModelConstants.SPACE))
                result = false;

            if (string.IsNullOrEmpty(LastName) || string.IsNullOrWhiteSpace(LastName))
                result = false;

            if (LastName.Length > ModelConstants.MAX_LAST_NAME_LENGTH)
                result = false;

            if (LastName.Contains(ModelConstants.SPACE))
                result = false;

            if (string.IsNullOrEmpty(Password) || string.IsNullOrWhiteSpace(Password))
                result = false;

            if (Password.Length < ModelConstants.MIN_PASSWORD_LENGTH || Password.Length > ModelConstants.MAX_PASSWORD_LENGTH)
                result = false;

            if (Password.Contains(ModelConstants.SPACE))
                result = false;

            if (!Regex.IsMatch(Email, ModelConstants.EMAIL_REGULAR_EXPRESSION))
                result = false;

            if (Email.Length > ModelConstants.MAX_EMAIL_LENGTH)
                result = false;

            if (Phone != null && Phone.Length > ModelConstants.MAX_PHONE_LENGTH)
                result = false;

            return result;
        }

        #endregion

        #region IEquatable<User> Implementation

        public bool Equals(User other)
        {
            if (other == null)
                return false;

            if (other.Login.Equals(Login))
                return true;

            return false;
        }

        #endregion

        #region Fields

        private bool m_NewProductsReporting = true;
        private DateTime m_StatusChangeDate = default(DateTime);
        private int m_Discount = default(int);
        private Enumerators.UserStatus m_UserStatus = Enumerators.UserStatus.User;

        #endregion
    }
}
